#pragma once

#include <httplib.h>
#include <spdlog/spdlog.h>
#include "../util/server.hh"
#include "../util/response.hh"
#include "../poco/word.hh"
#include "../service/word-service.hh"

namespace WordMemory
{
    class WordController
    {
    public:
        static void registerBusiness()
        {
            Server::instance().regist<Server::BusType::GET>("/api/words", getWord);
            Server::instance().regist<Server::BusType::POST>("/api/words/custom/example", addCustomExample);
            Server::instance().regist<Server::BusType::POST>("/api/words/custom/mnemonic", addCustomMnemonic);
            Server::instance().regist<Server::BusType::POST>("/api/words/status", updateStatus);

            spdlog::info("Word controller registered");
        }

    private:
        static void getWord(const httplib::Request &req, httplib::Response &res)
        {
            try
            {
                if (!req.has_param("user_id") || !req.has_param("word")) {
                    throw ControllerExcept("user_id and word parameters are required");
                }
                int user_id = std::stoi(req.get_param_value("user_id"));
                std::string word_text = req.get_param_value("word");

                if (word_text.empty()) { // Already checked by has_param, but good practice
                    throw ControllerExcept("Word parameter cannot be empty");
                }

                res.status = 200;
                res.set_content(ResponseMessage::success(
                        WordService::instance().getWordWithFavoriteStatus(user_id, word_text).to_json()
                        ), "application/json");

                spdlog::info("Fetched word '{}' for user_id {} with favorite status", word_text, user_id);
            }
            catch (const std::invalid_argument &e) {
                res.status = 400;
                res.set_content(ResponseMessage::error("Invalid user_id format: " + std::string(e.what())), "application/json");
                spdlog::error("Invalid parameter in getWord: {}", e.what());
            }
            catch (const ControllerExcept &e) {
                res.status = 400; // Bad request (e.g. missing params)
                res.set_content(ResponseMessage::error(e.what()), "application/json");
                spdlog::error("Controller error in getWord: {}", e.what());
            }
            catch (const RepositoryExcept &e) { // Catching specific exception from service/repo
                res.status = 404; // Word not found or access denied
                res.set_content(ResponseMessage::error(e.what()), "application/json");
                spdlog::warn("Repository error in getWord (word likely not found or no access): {}", e.what());
            }
            catch (const ServerExcept &e) { // General server/service error
                res.status = 500;
                res.set_content(ResponseMessage::error(e.what()), "application/json");
                spdlog::error("Server error in getWord: {}", e.what());
            }
        }

        static void addCustomExample(const httplib::Request &req, httplib::Response &res)
        {
            try
            {
                Json::Value json;
                Json::Reader reader;

                if (!reader.parse(req.body, json))
                    throw ControllerExcept("Invalid JSON");


                int word_id = json["word_id"].asInt();
                std::string example = json["example"].asString();
                std::string translation = json["translation"].asString();

                WordService::instance().addExample(word_id, example, translation);

                res.status = 200;
                res.set_content(ResponseMessage::success(), "application/json");

                spdlog::info("Added example for word_id {}", word_id);
            }
            catch (const ControllerExcept &e)
            {
                res.status = 400;
                res.set_content(ResponseMessage::error(e.what()), "application/json");

                spdlog::error("Failed to add example: {}", e.what());
            }
        }

        static void addCustomMnemonic(const httplib::Request &req, httplib::Response &res)
        {
            try
            {
                Json::Value json;
                Json::Reader reader;
                if (!reader.parse(req.body, json))
                    throw ControllerExcept("Invalid JSON");

                int word_id = json["word_id"].asInt();
                std::string mnemonic = json["mnemonic"].asString();

                WordService::instance().addMnemonic(word_id, mnemonic);

                res.status = 200;
                res.set_content(ResponseMessage::success(), "application/json");

                spdlog::info("Added mnemonic for word_id {}", word_id);
            }
            catch (const ControllerExcept &e)
            {
                res.status = 400;
                res.set_content(ResponseMessage::error(e.what()), "application/json");

                spdlog::error("Failed to add mnemonic: {}", e.what());
            }
        }

        static void updateStatus(const httplib::Request &req, httplib::Response &res)
        {
            try
            {
                Json::Value json;
                Json::Reader reader;
                if (!reader.parse(req.body, json))
                    throw ControllerExcept("Invalid JSON");

                int user_id = json["user_id"].asInt();
                int word_id = json["word_id"].asInt();
                std::string status = json["status"].asString();

                WordService::instance().updateStatus(user_id, word_id, status);

                res.status = 200;
                res.set_content(ResponseMessage::success(), "application/json");

                spdlog::info("Updated status {} for user_id {}, word_id {}", status, user_id, word_id);
            }
            catch (const ControllerExcept &e)
            {
                res.status = 400;
                res.set_content(ResponseMessage::error(e.what()), "application/json");

                spdlog::error("Failed to update status: {}", e.what());
            }
        }
    };
}